// NOWHINE NC009 <- Shared file with system team so uses non-CamX file naming
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2017-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  ica10setting.cpp
/// @brief IPE ICA10 setting calculation
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "ica10setting.h"
#include "Process_ICA.h"
#include "NcLibWarp.h"

CAMX_STATIC_ASSERT(sizeof(ICA_REG) == ICAREGSIZE);
CAMX_STATIC_ASSERT(sizeof(NCLIB_CONTEXT_ICA) == NCLIBCONTEXTICA);
CAMX_STATIC_ASSERT(sizeof(ICA_Chromatix) == ICAChromatix);
CAMX_STATIC_ASSERT(sizeof(struct FDData) == sizeof(FD_CONFIG_CONTEXT));

static const UINT ICAMaxPerspectiveTransform           = 9;
static const UINT ICAParametersPerPerspectiveTransform = 9;
static const UINT InterpolationCoeffSets               = 16;
static const UINT GridAssistRows                       = 16;
static const UINT GridAssistColumns                    = 16;


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ICA10Setting::ValidateContextParams
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL ICA10Setting::ValidateContextParams(
    const ICA10InputData*             pInput)
{
    CAMX_UNREFERENCED_PARAM(pInput);
    // Taken care by NClib currently

    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ICA10Setting::DumpContextParams
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL ICA10Setting::DumpContextParams(
    const ICA10InputData*          pInput,
    ica_1_0_0::ica10_rgn_dataType* pData)
{
    NcLibWarp* pWarp = static_cast<NcLibWarp*>(pInput->pCurrICAInData);;

    if (NULL != pWarp)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "warp enable %d , center %d, row %d, column %d",
                         pWarp->matrices.enable,
                         pWarp->matrices.centerType,
                         pWarp->matrices.numRows,
                         pWarp->matrices.numColumns);
        CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "width  %d, height %d",
                         pWarp->matrices.transformDefinedOn.widthPixels,
                         pWarp->matrices.transformDefinedOn.heightLines);
        for (UINT i = 0; i < ICAMaxPerspectiveTransform; i++)
        {
            for (UINT j = 0; j < ICAParametersPerPerspectiveTransform; j++)
            {
                CAMX_LOG_VERBOSE(CamxLogGroupIQMod, " matrices [%d] [%d] :  %f",
                                 i , j, pWarp->matrices.perspMatrices[i].T[j]);
            }
        }
        CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "dump %f", pData->y_interpolation_type);
    }
    return TRUE;
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ICA10Setting::MapChromatixMod2ICAv10Chromatix
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL  ICA10Setting::MapChromatixMod2ICAv10Chromatix(
    const ICA10InputData*                   pInput,
    ica_1_0_0::chromatix_ica10_reserveType* pReserveData,
    ica_1_0_0::ica10_rgn_dataType*          pData,
    VOID*                                   pChromatix)
{

    ICA_Chromatix*  pIcaChromatix = static_cast<ICA_Chromatix*>(pChromatix);

    pIcaChromatix->top.y_interpolation_type = IQSettingUtils::RoundFLOAT(pData->y_interpolation_type);

    pIcaChromatix->opg.opg_invalid_output_treatment_calculate = pReserveData->opg_invalid_output_treatment_calculate;
    pIcaChromatix->opg.opg_invalid_output_treatment_y         = pReserveData->opg_invalid_output_treatment_y;
    pIcaChromatix->opg.opg_invalid_output_treatment_cb        = pReserveData->opg_invalid_output_treatment_cb;
    pIcaChromatix->opg.opg_invalid_output_treatment_cr        = pReserveData->opg_invalid_output_treatment_cr;

    CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "cal %d, y %d, cb %d, cr %d, grid %d",
                     pReserveData->opg_invalid_output_treatment_calculate,
                     pReserveData->opg_invalid_output_treatment_y,
                     pReserveData->opg_invalid_output_treatment_cb,
                     pReserveData->opg_invalid_output_treatment_cr,
                     pInput->pChromatix->enable_section.ctc_transform_grid_enable);

    // Add static assert
    for (UINT idx = 0; idx < InterpolationCoeffSets; idx++)
    {
        pIcaChromatix->opg.opg_interpolation_lut_0[idx] =
            IQSettingUtils::RoundFLOAT(pData->opg_interpolation_lut_0_tab.opg_interpolation_lut_0[idx]);
        pIcaChromatix->opg.opg_interpolation_lut_1[idx] =
            IQSettingUtils::RoundFLOAT(pData->opg_interpolation_lut_1_tab.opg_interpolation_lut_1[idx]);
        pIcaChromatix->opg.opg_interpolation_lut_2[idx] =
            IQSettingUtils::RoundFLOAT(pData->opg_interpolation_lut_2_tab.opg_interpolation_lut_2[idx]);

        CAMX_LOG_VERBOSE(CamxLogGroupPProc, " lut 0 %f, lut 1 %f, lut 2 %f",
                         pData->opg_interpolation_lut_0_tab.opg_interpolation_lut_0[idx],
                         pData->opg_interpolation_lut_1_tab.opg_interpolation_lut_1[idx],
                         pData->opg_interpolation_lut_2_tab.opg_interpolation_lut_2[idx]);
    }


    // Add static assert
    for (UINT idx = 0; idx < ICAGridRegSize; idx++)
    {
        pIcaChromatix->ctc.ctc_grid_x[idx] = IQSettingUtils::RoundFLOAT(pData->ctc_grid_x_tab.ctc_grid_x[idx]);
        pIcaChromatix->ctc.ctc_grid_y[idx] = IQSettingUtils::RoundFLOAT(pData->ctc_grid_y_tab.ctc_grid_y[idx]);
        pIcaChromatix->distorted_input_to_undistorted_ldc_grid_x[idx] =
            IQSettingUtils::RoundFLOAT(
            pData->distorted_input_to_undistorted_ldc_grid_x_tab.distorted_input_to_undistorted_ldc_grid_x[idx]);
        pIcaChromatix->distorted_input_to_undistorted_ldc_grid_y[idx] =
            IQSettingUtils::RoundFLOAT(
            pData->distorted_input_to_undistorted_ldc_grid_y_tab.distorted_input_to_undistorted_ldc_grid_y[idx]);
        pIcaChromatix->undistorted_to_lens_distorted_output_ld_grid_x[idx] =
            IQSettingUtils::RoundFLOAT(
            pData->undistorted_to_lens_distorted_output_ld_grid_x_tab.undistorted_to_lens_distorted_output_ld_grid_x[idx]);
        pIcaChromatix->undistorted_to_lens_distorted_output_ld_grid_y[idx] =
            IQSettingUtils::RoundFLOAT(
            pData->undistorted_to_lens_distorted_output_ld_grid_y_tab.undistorted_to_lens_distorted_output_ld_grid_y[idx]);
    }

    pIcaChromatix->ctc.ctc_transform_grid_enable =
        (NULL != pInput->pChromatix) ? pInput->pChromatix->enable_section.ctc_transform_grid_enable : 0;
    // No grid in chromatix
    pIcaChromatix->ctc.ctc_transform_grid_enable = 0;
    return TRUE;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ICA10Setting::CalculateHWSetting
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL ICA10Setting::CalculateHWSetting(
    const ICA10InputData*                   pInput,
    ica_1_0_0::ica10_rgn_dataType*          pData,
    ica_1_0_0::chromatix_ica10_reserveType* pReserveData,
    VOID*                                   pOutput)
{
    BOOL   result                 = TRUE;
    BOOL   icaIsGridEnabledByFlow = 0;
    BOOL   icaPerspectiveEnabled  = 0;
    UINT32 ret                    = 0;

    if ((NULL != pInput) && (NULL != pData) && (NULL != pOutput))
    {
        ICA10UnpackedField* pUnpackedField = static_cast<ICA10UnpackedField*>(pOutput);
        IcaParameters*      pIcaParams     = static_cast<IcaParameters*>(pUnpackedField->pIcaParameter);

        ICA_REG*            pRegData       = static_cast<ICA_REG*>(pInput->pNCRegData);
        ICA_Chromatix*      pChromatixData = static_cast<ICA_Chromatix*>(pInput->pNCChromatix);

        // Intialize Warp stucture used by NcLib
        NcLibWarp*          pCurInWarp     = static_cast<NcLibWarp*>(pInput->pCurrICAInData);
        NcLibWarp*          pCurRefWarp    = static_cast<NcLibWarp*>(pInput->pCurrICARefData);
        NcLibWarp*          pPrevInWarp    = static_cast<NcLibWarp*>(pInput->pPrevICAInData);
        NcLibWarpGeomOut*   pGeomOut       = static_cast<NcLibWarpGeomOut*>(pInput->pWarpGeomOut);

        NcLibPerspTransformSingle  perspectiveMatrices[9];
        NcLibWarpGridCoord         grid[829];
        NcLibWarpGridCoord         gridExtrapolate[4];
        NcLibWarp                  warpOut;
        NcLibWarp*                 pRefWarp = pCurRefWarp;

        // Intialize Assist grid stucture used by NcLib
        NcLibWarpBuildAssistGridOut* pCurrAssist =
            static_cast<NcLibWarpBuildAssistGridOut*>(pInput->pCurWarpAssistData);
        NcLibWarpBuildAssistGridOut* pPrevAssist =
            static_cast<NcLibWarpBuildAssistGridOut*>(pInput->pPrevWarpAssistData);

        NcLibWarpBuildAssistGridIn      assistIn;
        NcLibWarpGeomIn                 geomIn;
        // Update with pointer from IQ module
        NcLibCalcMctfIn                 mctf;

        // Allocate and asssign
        IQSettingUtils::Memset(&assistIn, 0x0, sizeof(assistIn));
        IQSettingUtils::Memset(&geomIn, 0x0, sizeof(geomIn));
        IQSettingUtils::Memset(&mctf, 0x0, sizeof(mctf));

        // Set Defaults values for Firmware Struct
        SetDefaultsForIcaStruct(pIcaParams);

        // Set default values for ICA REG
        SetDefaultVal_ICA_REG(pRegData);

        // Set default chromatix data
        SetDefaultVal_ICA_Chromatix(pChromatixData);
        DumpContextParams(pInput, pData);

        // map chromatix parameters or pick from input if provided
        MapChromatixMod2ICAv10Chromatix(pInput, pReserveData, pData,  pChromatixData);

        pCurInWarp             = static_cast<NcLibWarp*>(pInput->pCurrICAInData);

        geomIn.inputSize            = static_cast<ImageDimensions*>(pInput->pImageDimensions);
        geomIn.stabilizationMargins = static_cast<ImageDimensions*>(pInput->pMarginDimensions);
        geomIn.zoomWindow           = static_cast<IpeZoomWindow*>(pInput->pZoomWindow);
        geomIn.ifeZoomWindow        = static_cast<IpeZoomWindow*>(pInput->pIFEZoomWindow);

        // Need to get proper values for FD/ANR/TF/ alignment domain/ lnr domain
        geomIn.fdConfig                = reinterpret_cast<FD_CONFIG_CONTEXT*>(pInput->pFDData);
        geomIn.isFdConfigFromPrevFrame = 1;
        geomIn.alignmentDomain         = INPUT_IMAGE_DOMAIN;
        geomIn.ica1UpScaleRatio        = 1.0;
        geomIn.inputGridsPrevFrame     = (TRUE == geomIn.isFdConfigFromPrevFrame) ? pPrevAssist : NULL;
        geomIn.inputGrids              = pCurrAssist;

        if (1 == pInput->IPEPath)
        {
            CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "REF: %d perspective %d, perspective c %d, r %d, w %d , h %d",
                             pInput->frameNum,
                             pCurRefWarp->matrices.enable,
                             pCurRefWarp->matrices.numColumns,
                             pCurRefWarp->matrices.numRows,
                             pCurRefWarp->matrices.transformDefinedOn.widthPixels,
                             pCurRefWarp->matrices.transformDefinedOn.heightLines);

            icaIsGridEnabledByFlow = pCurRefWarp->grid.enable;
            icaPerspectiveEnabled  = pCurRefWarp->matrices.enable;
            if (TRUE == result)
            {
                // calculate MCTF matrix of current frame
                ret = NcLibWarpConvertToVirtualDomain(pCurRefWarp, pCurRefWarp);
                result = (0 == ret) ? TRUE : FALSE;
                CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "NcLibWarpConvertToVirtualDomain ref %d, path %d",
                                 result, pInput->IPEPath);
            }

            if (TRUE == result)
            {
                /* calculate MCTF matrix */
                warpOut.grid.grid = grid;
                warpOut.grid.gridExtrapolate   = gridExtrapolate;
                warpOut.matrices.perspMatrices = perspectiveMatrices;

                // geomIn.alignment          = pCurRefWarp; // check
                // set correct value

                mctf.alignmentDomain      = INPUT_IMAGE_DOMAIN;
                mctf.inputSize            = geomIn.inputSize;
                mctf.stabilizationMargins = geomIn.stabilizationMargins;
                mctf.alignment            = pCurRefWarp;
                mctf.inputWarp            = pCurInWarp;
                mctf.inputGridsPrevFrame  = pPrevAssist;
                mctf.inputGrids           = NULL;

                if (TRUE == CheckMctfTransformCondition(
                    static_cast<VOID*>(&mctf), static_cast<VOID*>(&warpOut), pInput->mctfEis))
                {
                    pRefWarp = &warpOut;
                    ret = NcLibCalcMctfTransform(&mctf, &warpOut);
                    result = (0 == ret) ? TRUE : FALSE;
                    CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "NcLibCalcMctfTransform %d, path %d", result, pInput->IPEPath);
                }
            }

            if (TRUE == result)
            {
                // Validate parameters input to NCLib as debug settings/
                // Currently part of NCLib
                result = ICA_ProcessNcLib(pChromatixData,
                    static_cast<uint8_t>(icaIsGridEnabledByFlow),
                    pRegData,
                    static_cast<IcaParameters*>(pUnpackedField->pIcaParameter));
                CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "ICA_ProcessNcLib : result %d, path %d", result, pInput->IPEPath);

            }

            if (TRUE == result)
            {
                if ((TRUE == pRefWarp->grid.enable) ||
                    (TRUE == pRefWarp->matrices.enable))
                {
                    result = ICA_ProcessNonChromatixParams(&pRefWarp->grid,
                                                           &pRefWarp->matrices,
                                                           static_cast<uint8_t>(icaIsGridEnabledByFlow),
                                                           1,
                                                           pRegData,
                                                           static_cast<IcaParameters*>(pUnpackedField->pIcaParameter));
                    CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "ICA_ProcessNonChromatixParams : result %d, path %d",
                                     result, pInput->IPEPath);
                }
            }
        }
        else
        {
            CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "INPUT: %d,  perspective %d, perspective c %d, r %d, w %d , h %d",
                             pInput->frameNum,
                             pCurInWarp->matrices.enable,
                             pCurInWarp->matrices.numColumns,
                             pCurInWarp->matrices.numRows,
                             pCurInWarp->matrices.transformDefinedOn.widthPixels,
                             pCurInWarp->matrices.transformDefinedOn.heightLines);
            icaIsGridEnabledByFlow = pCurInWarp->grid.enable;
            icaPerspectiveEnabled = pCurInWarp->matrices.enable;
            if ((TRUE  == pInput->mctfEis)       &&
                ((TRUE == icaIsGridEnabledByFlow) ||
                (TRUE  == icaPerspectiveEnabled)))
            {
                // Convert input parameters to virtual domain
                ret    = NcLibWarpConvertToVirtualDomain(pCurInWarp, pCurInWarp);
                result = (0 == ret) ? TRUE : FALSE;
                CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "NcLibWarpConvertToVirtualDomain %d, path %d",
                                 result, pInput->IPEPath);
                if (TRUE == result)
                {
                    // Build assist grid of current frame and calculate geometric parameters
                    assistIn.in         = pCurInWarp;
                    assistIn.numColumns = GridAssistColumns;
                    assistIn.numRows    = GridAssistRows;
                    if (NULL != pCurrAssist)
                    {
                        ret = NcLibWarpBuildAssistGrid(&assistIn, pCurrAssist);
                        result = (0 == ret) ? TRUE : FALSE;
                        CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "NcLibWarpBuildAssistGrid %d, path %d",
                                         result, pInput->IPEPath);
                    }
                }

                if ((TRUE == result) && (NULL != pCurrAssist))
                {
                    pCurrAssist->inputWarp = pCurInWarp;
                    ret                    = NcLibWarpGeometries(&geomIn, pGeomOut);
                    result                 = (0 == ret) ? TRUE : FALSE;
                    CAMX_LOG_VERBOSE(CamxLogGroupIQMod, " NcLibWarpGeometries %d, path %d",
                                     result, pInput->IPEPath);
                }
            }

            if (TRUE == result)
            {
                // Validate parameters input to NCLib as debug settings/
                // Currently part of NCLib
                result = ICA_ProcessNcLib(pChromatixData,
                                          static_cast<uint8_t>(icaIsGridEnabledByFlow),
                                          pRegData,
                                          static_cast<IcaParameters*>(pUnpackedField->pIcaParameter));
                CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "ICA_ProcessNcLib : result %d, path %d", result, pInput->IPEPath);

            }

            if (TRUE == result)
            {
                if ((TRUE == pCurInWarp->grid.enable) ||
                    (TRUE == pCurInWarp->matrices.enable))
                {
                    result = ICA_ProcessNonChromatixParams(&pCurInWarp->grid,
                                                           &pCurInWarp->matrices,
                                                           static_cast<uint8_t>(icaIsGridEnabledByFlow),
                                                           1,
                                                           pRegData,
                                                           static_cast<IcaParameters*>(pUnpackedField->pIcaParameter));
                    CAMX_LOG_VERBOSE(CamxLogGroupIQMod, "ICA_ProcessNonChromatixParams : result %d, path %d",
                                     result, pInput->IPEPath);
                }
            }

            pUnpackedField->pCurrICAInData      = pCurInWarp;
            pUnpackedField->pPrevICAInData      = pPrevInWarp;
            pUnpackedField->pCurrWarpAssistData = pCurrAssist;
            pUnpackedField->pPrevWarpAssistData = pPrevAssist;
            pUnpackedField->pWarpGeometryData   = pGeomOut;
        }
    }
    return result;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// ICA10Setting::CheckMctfTransformCondition
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
BOOL ICA10Setting::CheckMctfTransformCondition(
    VOID* pMCTF,
    VOID* pWarpOut,
    BOOL  mctfEis)
{
    NcLibCalcMctfIn* pIn = static_cast<NcLibCalcMctfIn*>(pMCTF);
    NcLibWarp*       pOut = static_cast<NcLibWarp*>(pWarpOut);

    if (NULL  == pIn->alignment ||
        NULL  == pIn->inputGridsPrevFrame ||
        NULL  == pIn->inputGridsPrevFrame->assistGrid ||
        NULL  == pIn->inputGridsPrevFrame->inputWarp ||
        NULL  == pIn->inputWarp ||
        NULL  == pIn->inputSize ||
        NULL  == pIn->stabilizationMargins ||
        NULL  == pOut->matrices.perspMatrices ||
        FALSE == mctfEis)
    {
        CAMX_LOG_VERBOSE(CamxLogGroupIQMod, " alignemnt %p, inputGridsPrevFrame %p"
                         "inputWarp %p, inputSize %p, stabilizationMargins %p, perspMatrices %p, mctfEis %d",
                         pIn->alignment, pIn->inputGridsPrevFrame, pIn->inputWarp, pIn->inputSize,
                         pIn->stabilizationMargins, pOut->matrices.perspMatrices, mctfEis);
        if (NULL != pIn->inputGridsPrevFrame)
        {
            CAMX_LOG_INFO(CamxLogGroupIQMod, " PassistG %p, PinputWarp %p,",
                          pIn->inputGridsPrevFrame->assistGrid,
                          pIn->inputGridsPrevFrame->inputWarp);

        }
        return FALSE;
    }

    return TRUE;
}
